package cn.com.lms.business.livecourse.service;

import cn.com.lms.business.core.constant.CourseTypeEnum;
import cn.com.lms.business.core.constant.BNZConstants;
import cn.com.lms.business.core.util.FBUtils;
import cn.com.lms.business.core.util.SystemUserUtil;
import cn.com.lms.business.course.persistence.entity.FbCourseInfo;
import cn.com.lms.business.course.service.FbCourseInfoService;
import cn.com.lms.business.livecourse.cache.LiveCourseCache;
import cn.com.lms.business.livecourse.persistence.entity.AliLiveStream;
import cn.com.lms.business.livecourse.persistence.entity.CourseChatRoom;
import cn.com.lms.business.livecourse.persistence.entity.CourseLive;
import cn.com.lms.business.livecourse.persistence.entity.vod.AddLiveRecordVideoCompleteInfo;
import cn.com.lms.business.livecourse.persistence.repository.CourseLiveRepository;
import cn.com.lms.business.livecourse.util.CourseTypeUtil;
import cn.com.lms.business.user.persistence.entity.SysUserVo;
import com.bnzj.core.exception.BusinessException;
import com.bnzj.core.persistence.BaseService;
import com.bnzj.core.persistence.query.CompareExpression;
import com.bnzj.core.persistence.query.CompareType;
import com.bnzj.core.persistence.query.IExpression;
import com.bnzj.core.persistence.query.QueryHelpBean;
import com.bnzj.core.rest.ResponseResult;
import com.bnzj.core.rest.ResultCode;
import com.bnzj.core.webmvc.util.WebMvcUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.*;

/**
 * CourseLiveService
 *
 * @author barry
 * @date 2020/3/16
 **/
@Service
public class CourseLiveService extends BaseService<CourseLiveRepository, CourseLive, Long> {

    @Autowired
    AliLiveStreamService aliLiveStreamService;

    @Autowired
    AliVodService aliVodService;

    @Autowired
    FbCourseInfoService fbCourseInfoService;

    @Autowired
    LiveCourseCache liveCourseCache;

    @Autowired
    AliRtcService aliRtcService;

    /**
     * 创建课程直播流信息记录
     *
     * @param courseId
     * @return
     */
    public CourseLive createCourseLive(long courseId, Date liveStartTime) {
        // 生成流信息
        // 创建流名称
        String streamName = "stream-" + courseId + "-" + System.currentTimeMillis() / 1000;
        AliLiveStream stream = null;
        try {
            long expireTime = liveStartTime.getTime() / 1000 + 12 * 3600;    // 指定过期时间为开播过期后的12小时
            stream = aliLiveStreamService.getStreams(streamName, expireTime); // 需要使用课程开始时间，暂使用课程创建时间
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }

        // 添加直播课程的流记录
        CourseLive courseLive = new CourseLive();
        courseLive.setCourseInfoId(courseId);
        courseLive.setCreateTime(new Timestamp(System.currentTimeMillis()));
        courseLive.setExpireTime(new Timestamp(stream.getExpireTime() * 1000));
        courseLive.setLastStatusUpdateTime(new Timestamp(System.currentTimeMillis()));
        courseLive.setStreamName(streamName);
        courseLive.setPushUrl(stream.getPushStreamUrl());
        courseLive.setPullUrl(stream.getPullStreamUrl());
        courseLive.setPullUrlFlv(stream.getPullStreamUrlFlv());
        courseLive.setPullUrlM3u8(stream.getPullStreamUrlM3u8());
        courseLive.setStatus(0);    // 状态 0未使用
        courseLive = this.save(courseLive);
//        System.out.println(courseLive.toString());
        return courseLive;
    }

    /**
     * 开播时间改变时，更新直播相关信息
     *
     * @param courseInfo
     */
    @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class)
    public void updateCourseLiveInfoWhenLiveStartTimeChange(FbCourseInfo courseInfo) throws Exception {
        // 生成流信息
        // 创建流名称
        String streamName = "stream-" + courseInfo.getId() + "-" + System.currentTimeMillis() / 1000;
        AliLiveStream stream = null;
        try {
            long expireTime = courseInfo.getLiveStartTime().getTime() / 1000 + 12 * 3600;    // 指定过期时间为开播过期后的12小时
            stream = aliLiveStreamService.getStreams(streamName, expireTime); // 需要使用课程开始时间，暂使用课程创建时间
        } catch (ParseException e) {
            e.printStackTrace();
            throw new Exception(e.getMessage());
        }
        // 更新直播流相关信息
        CourseLive courseLive = courseLiveInfo(courseInfo.getId());
        courseLive.setExpireTime(new Timestamp(stream.getExpireTime() * 1000));
        courseLive.setStreamName(streamName);
        courseLive.setPushUrl(stream.getPushStreamUrl());
        courseLive.setPullUrl(stream.getPullStreamUrl());
        courseLive.setPullUrlFlv(stream.getPullStreamUrlFlv());
        courseLive.setPullUrlM3u8(stream.getPullStreamUrlM3u8());
        try {
            this.saveAndFlush(courseLive);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("更新直播流相关信息失败" + e.getMessage());
        }
    }


    /**
     * 直播转点播录制完成处理
     *
     * @param info 阿里云点播回调信息
     * @return
     */
    @Transactional
    public int vodRecordComplete(AddLiveRecordVideoCompleteInfo info) {
        // 获取录制文件信息（点播视频播放链接（源文件链接）、时长等）
        Map recordInfo = aliVodService.getMezzanineInfo(info.getVideoId());
        String playUrl = "";
        String duration = "";
        if (null != recordInfo) {
            playUrl = (String) recordInfo.get("playUrl");
            duration = (String) recordInfo.get("duration");
        }
//        System.out.println("duration = " + duration);
        CourseLive courseLive = this.repository.findByStreamName(info.getStreamName());
        if (null == courseLive || courseLive.getCourseInfoId() < 0) {
            return 0;
        }

        if (2 != courseLive.getStatus()) {  // 非主动停止直播的情况（如直接关闭网页）
            // 停止rtc直播任务
            HashMap<String, Object> taskResult = aliRtcService.stopRtcLive(courseLive.getStreamName());
            if (!((boolean) taskResult.get("success"))) {
                return 0;
            }

            // 释放聊天室房间占用
            courseChatRoomService.releaseRoom(courseLive.getCourseInfoId());
        }

        // 更新课程的视频信息，直播状态 （3录制完成，当未启用直转点转码时，录制完成将是最终状态）、播放地址
        this.repository.modifyCourseLiveVideoInfoByStreamName(info.getStreamName(), 3, playUrl);

        // 更新直播记录的对应vid和直播状态
        return this.repository.vodRecordComplete(info.getStreamName(), info.getVideoId());
    }

    /**
     * 通过课程id获取课程直播信息
     *
     * @param courseId
     * @return
     */
    public CourseLive courseLiveInfo(long courseId) throws Exception {
        Map clMap = this.repository.findByCourseId(courseId);
        ArrayList<Map<String, Object>> clMaps = new ArrayList<>();
        clMaps.add(clMap);
        List<CourseLive> courseLives = FBUtils.convertListMapToListBean(clMaps, CourseLive.class);
        CourseLive courseLive = courseLives.size() > 0 ? courseLives.get(0) : null;
        return courseLive;
    }

    /**
     * 修改课程直播状态
     *
     * @param courseId 课程id
     * @param status   直播状态：1开始直播；2结束直播
     * @return
     */
    @Transactional
    public int modifyLiveStatus(long courseId, int status) throws Exception {
        // 获取课程直播信息
        Map clMap = this.repository.findByCourseId(courseId);
        ArrayList<Map<String, Object>> clMaps = new ArrayList<>();
        clMaps.add(clMap);
        List<CourseLive> courseLives = FBUtils.convertListMapToListBean(clMaps, CourseLive.class);
        CourseLive courseLive = courseLives.size() > 0 ? courseLives.get(0) : null;
        if (null == courseLive) {
            return 0;
        }

        if (1 == status) {
            // 直播状态只能是待直播或直播中，才能开启（或重启）直播
            if (courseLive.getStatus() > 1) {
                return 0;
            }
            if (1 == courseLive.getStatus()) {
                return 1;   // 不重复记录
            }
        }
        if (2 == status) {
            // 直播状态已结束（已关闭直播或已直接录制完成状态），不处理
            if (2 <= courseLive.getStatus()) {
                return 1;
            }
            // 只能为直播中的状态时，才能变更为停止直播状态
            if (1 != courseLive.getStatus()) {
                return 0;
            }
        }

        if (2 == status) {
            // 释放聊天室房间占用
            courseChatRoomService.releaseRoom(courseId);
        }
        // 更新直播课程的直播状态
        if (1 == status) {
            // 同时记录真实开播时间
            this.repository.modifyCourseLiveStatusAndTime(courseId, status, new Date());
        } else {
            this.repository.modifyCourseLiveStatus(courseId, status);
        }
        // 更新直播信息的直播状态
        return this.repository.modifyLiveStatus(courseId, status);
    }

    @Autowired
    CourseChatRoomService courseChatRoomService;

    @Transactional
    public void saveLiveVodInfo(String vid, String playUrl, int duration) {
        // 修改live的状态为4已转码完成
        this.repository.modifyLiveStatusByVid(vid, 4);
        // 保存vod信息到course
        this.repository.saveCoursePlayUrlByVid(vid, playUrl, duration, 4);
    }

    /**
     * 增加或减少观看人数
     *
     * @param courseId 课程id
     * @param type     处理类型：1增加；2减少
     * @return
     */
    public Long incrOrDecrViewersCount(long courseId, int type) {
        Long count = 0L;
        if (1 == type) {
            count = liveCourseCache.incrLiveViewersCount(courseId);
        } else {
            count = liveCourseCache.decrLiveViewersCount(courseId);
        }
        return count;
    }

    /**
     * 增加课程观看者人数
     *
     * @param courseId 课程id
     */
    @Transactional
    public void incrCourseViewersCount(long courseId) {
        int result = this.repository.incrCourseViewersCount(courseId);
        if (0 == result) {
            System.out.println("增加课程观看者人数失败，courseId = " + courseId);
        }
    }

    /**
     * 用户相关的直播课程列表
     *
     * @param request
     * @return
     */
    public ResponseResult courseList(HttpServletRequest request) {
        int type = Integer.parseInt(request.getParameter("liveStatusType"));
        Pageable pageable = null;
        if (1 == type) {
            Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "live_status");
            Sort.Order order2 = new Sort.Order(Sort.Direction.ASC, "live_start_time");
            pageable = WebMvcUtils.initPage(request, Sort.by(order1, order2));
        } else {
            Sort.Order order = new Sort.Order(Sort.Direction.DESC, "live_start_time");
            pageable = WebMvcUtils.initPage(request, Sort.by(order));
        }

        SysUserVo user = SystemUserUtil.getCurrentUser();
        if (null == user) {
            return ResponseResult.bizException(new BusinessException("用户信息异常", String.valueOf(ResultCode.FAILURE)));
        }
        String title = request.getParameter("title");

        // 指定课程类型 直播
        List<Map<String, Object>> mapList = fbCourseInfoService.getCourseTypeDictionary(BNZConstants.COURSE_TYPE_CODE);
        long courseTypeId = CourseTypeUtil.getCourseTypeId(mapList, CourseTypeEnum.LIVE.getValue());

        QueryHelpBean queryHelpBean = getUserCourseListQueryHelperBean(user.getId(), type);
        IExpression titleCondition = CompareExpression.build("ci.title", CompareType.like, title);

        IExpression courseTypeIdCondition = CompareExpression.build("ci.course_type", CompareType.equal, courseTypeId);
        queryHelpBean.addWhere(titleCondition);
        queryHelpBean.addWhere(courseTypeIdCondition);
        queryHelpBean.setPageable(pageable);
        Page<Map<String, Object>> all = this.findAll(queryHelpBean);
        return ResponseResult.success(all);
    }

    /**
     * 用户相关课程列表helperBean
     *
     * @param userId 用户id
     * @param type   课程类型：1待直播和直播中的课程；2可回看的课程（录制保存完成和正在生成回访中）
     * @return
     */
    public QueryHelpBean getUserCourseListQueryHelperBean(Long userId, int type) {
        String selectSQL = " select a.*,ci.id,ci.title,ci.picture_url,ci.course_type,d.`name` AS courseTypeName,ci" +
                ".course_time,ci.live_status,ci.live_start_time,ci.create_time,ci.viewers_count";
        String whereSQL = " from (select ls.id detailId,ld.obj_id,ls.last_study_time,ls.finish_state,ls" +
                ".learning_hours,ld.id as stageDetailId,lp.id as planId,lp.plan_name as planName from " +
                "bnz_learning_student ls" +
                " inner join bnz_learning_stage_detail ld on ld.id=ls.stage_detail_id " +
                " inner join bnz_learning_plan lp on ld.plan_id=lp.id " +
                " where study_type= 1 and ls.user_id=" + userId +
                " ) a INNER JOIN bnz_course_info ci on ci.id=a.obj_id  and ci.is_delete=0 left join bnz_sys_dictionary d on ci.course_type=d.id where ci.is_delete=0 and ";
        if (1 == type) {
            whereSQL += "ci.live_status<2";
        } else {
            whereSQL += "ci.live_status>=2";
        }
        QueryHelpBean queryBean = new QueryHelpBean(selectSQL + whereSQL, "select count(1)" + whereSQL);
        return queryBean;
    }

    /**
     * 直播课程新增时，直播信息相关处理
     *
     * @param courseInfo
     * @throws Exception
     */
    @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class)
    public void handleLiveInfoWhenCourseSave(FbCourseInfo courseInfo) throws Exception {
        // 直播课程添加直播流信息记录
        Date currentDate = new Date();
        if (courseInfo.getLiveStartTime().getTime() <= currentDate.getTime()) {
            throw new Exception("直播开始时间需大于当前时间");
        }
        CourseLive courseLive = this.createCourseLive(courseInfo.getId(), courseInfo.getLiveStartTime());
        System.out.println("courseLive = " + courseLive);
        if (null == courseLive) {
            throw new Exception("添加直播流失败");
        }
        // 课程房间占用处理
        CourseChatRoom room = courseChatRoomService.getCourseChatRoom(courseInfo.getId(), courseInfo.getLiveStartTime());
        if (null == room) {
            throw new Exception("没有可用的直播房间");
        }
    }

    /**
     * 直播课程修改时，修改开播时间的相关直播信息处理
     *
     * @param courseInfo
     * @throws Exception
     */
    @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class)
    public void handleLiveInfoWhenCourseUpdateLiveTime(FbCourseInfo courseInfo) throws Exception {
        if (null == courseInfo || 0 == courseInfo.getId() || null == courseInfo.getLiveStartTime()) {
            throw new Exception("课程开播信息处理，课程信息异常");
        }

        // 直播课程添加直播流信息记录
        Date currentDate = new Date();
        if (courseInfo.getLiveStartTime().getTime() <= currentDate.getTime()) {
            throw new Exception("直播开始时间需大于当前时间");
        }

        try {
            // 开播时间改变时，更新直播相关信息
            updateCourseLiveInfoWhenLiveStartTimeChange(courseInfo);

            // 更新房间过期时间
            courseChatRoomService.updateRoomExpireTime(courseInfo.getId(), courseInfo.getLiveStartTime());
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
    }



}
